;; this is the current configuration for my gnucode.me,
;; propernaming.org, and gnu-hurd.com

(add-to-load-path (dirname (current-filename)))

(add-to-load-path "/home/joshua/prog/gnu/guix/guixrus")

(use-modules (gnu)
             (guix modules)
             ;;(secret nginx)
             (public-keys)
             ;;(gnucode-form)
             (nftables)
             (endlessh-service)
             ;;(opensmtpd-records)
             ;;(gnu services mail)
             (guixrus services opensmtpd)
             (gnu packages mail)
             ((gnu services mail)
              #:hide (opensmtpd-configuration
                      opensmtpd-configuration?
                      opensmtpd-service-type
                      %default-opensmtpd-config-file))
             )
(use-service-modules admin ; unattended-upgrades
                     avahi
                     certbot
                     ;; mail
                     mcron
                     messaging
                     networking
                     security
                     sysctl
                     ssh
                     vpn ;;wireguard
                     web)
(use-package-modules admin
                     certs
                     package-management
                     ssh
                     tls)

(define %nginx-deploy-hook
  (program-file
   "nginx-deploy-hook"
   #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
       (kill pid SIGHUP))))

(define %my-base-services
  (modify-services %base-services
    (guix-service-type config =>
                       (guix-configuration (inherit config)
                                           (discover? #t)
                                           (substitute-urls
                                            (append (list
                                                     "https://guix.tobias.gr")
                                                    %default-substitute-urls))
                                           (authorized-keys
                                            (append (list
                                                     ;; setting up guix deploy from dobby.
                                                     (local-file "./dobby-guix-signing-key.pub")
                                                     (plain-file
                                                      "guix.tobias.gr"
                                                      "(public-key
 (ecc
  (curve Ed25519)
  (q #E21911E159DB6D031A763509A255B054360A4A96F5668CBBAC48052E67D274D3#)
  )
 )
")
                                                     )))
                                           (extra-options '("--max-jobs=1"))))

    ;; security stuff.
    (sysctl-service-type config =>
                         (sysctl-configuration
                          (settings
                           (append
                            '(
                              ;;disable ipv6
                              ("net.ipv6.conf.all.disable_ipv6"        . "1")
                              ("net.ipv6.conf.all.disable_policy"      . "1")
                              ("net.ipv6.conf.default.disable_ipv6"    . "1")
                              ("net.ipv6.conf.default.disable_policy"  . "1")
                              ("net.ipv6.conf.enp0s10.disable_ipv6"    . "1")
                              ("net.ipv6.conf.enp0s10.disable_policy"  . "1")
                              ("net.ipv6.conf.lo.disable_ipv6"         . "1")
                              ("net.ipv6.conf.lo.disable_policy"       . "1")
                              ;; disable ebpf in kernel virtual machine for unprivledged users
                              ("sysctl kernel.unprivileged_bpf_disabled" . "1")
                              ("spec_store_bypass_disable" . "on")
                              ("spectre_v2" . "on")
                              ("lld_flush" . "on")
                              ;; need to enable apparmor for this...
                              ;;("lockdown" . "confidentiality")
                              ("init_on_alloc" . "1")
                              ("init_on_free"  . "1")
                              ("page_alloc.shuffle" . "1")
                              ;;("slab_nomerge")
                              ("vsyscall"      . "1")
                              ;; ("slub_debug" . "F")
                              ("randomize_kstack_offset" . "1")
                              ;; disable re-leading a running kernel
                              ("kernel.kexec_load_disabled" . "1")
                              ;; restrict kernel pointers
                              ("kernel.kptr_restrict" . "2")
                              ;; unprivledegd users cannot get perf events
                              ("kernel.perf_event_paranoid" . "3")
                              ;; only privledged users can use bpf
                              ("net.core.bpf_jit_harden" . "2")
                              ("kernel.unprivleged_bpf" . "1")
                              ;; prevest some proofing attacks
                              ("net.ipv4.conf.all.rp_filter" . "1")
                              ("net.ipv4.conf.default.rp_filter" . "1")
                              ;; disable icmp redirects and
                              ;; RFC1620 shared media redirects
                              ("net.ipv4.conf.all.accept_redirects" . "0")
                              ("net.ipv4.conf.all.secure_redirects" . "0")
                              ("net.ipv4.conf.all.send_redirects" . "0")
                              ("net.ipv4.conf.all.shared_media" . "0")
                              ("net.ipv4.conf.default.accept_redirects" . "0")
                              ("net.ipv4.conf.default.secure_redirects" . "0")
                              ("net.ipv4.conf.default.send_redirects" . "0")
                              ("net.ipv4.conf.default.shared_media" . "0")
                              ("net.ipv6.conf.all.accept_redirects" . "0")
                              ("net.ipv6.conf.default.accept_redirects" . "0")
                              ;; disallow source-routed packets
                              ("net.ipv4.conf.all.accept_source_route" . "0")
                              ("net.ipv4.conf.default.accept_source_route" . "0")
                              ("net.ipv6.conf.all.accept_source_route" . "0")
                              ("net.ipv6.conf.default.accept_source_route" . "0")
                              ;; disable pings sent to a broadcast address
                              ("net.ipv4.icmp_echo_ignore_broadcasts" . "1")
                              ;; disable bogus icmp error responses
                              ("net.ipv4.icmp_ignore_bogus_error_responses" . "1")

                              ;; protect against time-wait assassination hazards in tcp
                              ("net.ipv4.tcp_rfc1337" . "1")

                              ("net.ipv4.tcp_sack" . "0")
                              ("net.ipv4.tcp_dsack" . "0")

                              ("net.ipv4.tcp_timestamps" . "0")
                              ("vm.mmap_rnd_bits" . "32")
                              ("vm.mmap_rnd_compat_bits" . "16")
                              ("net.ipv4.icmp_echo_ignore_all" . "1")
                              )
                            %default-sysctl-settings))))))


;;(define %system)
(operating-system
 (host-name "copertino")
 (timezone "America/Chicago")
 (locale "en_US.UTF-8")
 ;; This goofy code will generate the grub.cfg
 ;; without installing the grub bootloader on disk.
 (bootloader (bootloader-configuration
              (bootloader
               (bootloader
                (inherit grub-bootloader)
                (installer #~(const #t))))))
 (file-systems (cons (file-system
                      (device "/dev/sda")
                      (mount-point "/")
                      (type "ext4"))
                     %base-file-systems))

 (swap-devices (list
                (swap-space (target "/dev/sdb"))))

 (initrd-modules (cons "virtio_scsi"    ; Needed to find the disk
                       %base-initrd-modules))

 (users (cons* (user-account
                (name "joshua")
                (group "users")
                ;; Adding the account to the "wheel" group
                ;; makes it a sudoer.
                (supplementary-groups '("wheel"))
                (home-directory "/home/joshua"))
               ;;                 (user-account
               ;;                  (name "vmail")
               ;;                  (group "vmail")
               ;;                  (home-directory "vmail")
               ;;                  (system? #t)
               ;;                  (comment "User that dovecot users to deliver emails
               ;; to /home/vmail/gnucode.me/joshua"))
               %base-user-accounts))

 ;; (groups (cons* (user-group
 ;;                 (name "vmail")
 ;;                 (system? #t))
 ;;                %base-groups))

 ;; I can read 'man 5 suoders' for tips about the syntax of suoders file.
 ;; the very end of the file has some examples.
 (sudoers-file
  (plain-file "sudoers"
              (string-append (plain-file-content %sudoers-specification)
                             (format #f "~a ALL = NOPASSWD: ALL~%"
                                     "joshua"))))

 (packages (cons* openssh-sans-x
                  %base-packages))

 (services (cons*
            (service dhcp-client-service-type)
            ;; guix daemon requires avahi
            (service avahi-service-type)

            (service certbot-service-type
                     (certbot-configuration
                      (email "jbranso@dismail.de")
                      (webroot "/srv/www")
                      (certificates
                       (list
                        (certificate-configuration
                         (name "gnucode.me")
                         (domains '("gnucode.me" "www.gnucode.me"
                                    "imap.gnucode.me"
                                    "smtp.gnucode.me"))
                         (deploy-hook %nginx-deploy-hook))
                        (certificate-configuration
                         (name "gnu-hurd.com")
                         (domains '("gnu-hurd.com" "www.gnu-hurd.com"))
                         (deploy-hook %nginx-deploy-hook))
                        (certificate-configuration
                         (name "propernaming.org")
                         (domains '("propernaming.org" "www.propernaming.org"))
                         (deploy-hook %nginx-deploy-hook))
                        ))))

            (service dovecot-service-type
                     (dovecot-configuration
                      (mail-location "maildir:/home/%n/Maildir")
                      (protocols
                       (list
                        (protocol-configuration
                         (name "imap")
                         ;; 3 was too few.  Sometimes I will have several email clients
                         ;; open.  So 5 is a better number.
                         (mail-max-userip-connections 5)
                         )
                        ;;(protocol-configuration name "lmtp")
                        ))

                      ;; I am hoping to set up LMTP, that way I can set up Sieve filtering.
                      ;; https://doc.dovecot.org/configuration_manual/sieve/configuration/
                      ;; https://doc.dovecot.org/configuration_manual/protocols/lmtp_server/#lmtp-server
                      ;; (services
                      ;;  (list
                      ;;   (service-configuration
                      ;;    (kind "imap"))))

                      ;; someone tries to login via joshua@gnucode.me
                      ;; this strips away that login username to "joshua"
                      ;; when I set up virtual users, I'll need to delete this!
                      ;; https://wiki.dovecot.org/DomainLost
                      ;; "%n-AT-%d"  -> joshua@gnucode.me -> joshua-AT-gnucode.me
                      (auth-username-format "%n")
                      (ssl-cert  "</etc/letsencrypt/live/gnucode.me/fullchain.pem")
                      (ssl-key "</etc/letsencrypt/live/gnucode.me/privkey.pem")
                      ))

            ;;(service gnucode -form-service-type)

            (service fail2ban-service-type
                     (fail2ban-configuration
                      (extra-jails
                       (list
                        (fail2ban-jail-configuration
                         (name "sshd")
                         (enabled? #t))))))

            (service nginx-service-type
                     (let ([default-listen (list "80"
                                                 "443 ssl http2"
                                                 "[::]:80"
                                                 "[::]:443 ssl http2"
                                                 )]
                           ;; tell browsers my site supports HTTPS, and tell them that it will
                           ;; at least work for 12 hours.  Gradually,  I will increase this number.
                           [default-raw-content (list "add_header Strict-Transport-Security max-age=18000;")]
                           [srv-root-dir "/srv/www/html/"]
                           [letsencrypt-dir "/etc/letsencrypt/live/"]
                           [letsencrypt-acme-challenge (nginx-location-configuration ;; for certbot
                                                        (uri "/.well-known")
                                                        (body (list "root /srv/www;")))])

                       (nginx-configuration
                        (server-blocks
                         (list
                          (nginx-server-configuration
                           (server-name '("gnucode.me"))
                           (listen default-listen)
                           (root "/srv/www/html/gnucode.me/site/")
                           (ssl-certificate (string-append letsencrypt-dir "gnucode.me/fullchain.pem"))
                           (ssl-certificate-key (string-append letsencrypt-dir "gnucode.me/privkey.pem"))
                           (raw-content default-raw-content)
                           (locations
                            (list
                             letsencrypt-acme-challenge ;; for certbot
                             (nginx-location-configuration
                              (uri "/form/")
                              (body '("proxy_pass http://127.0.0.1:8081;")))
                             (nginx-location-configuration
                              (uri "/craggy-hurd/")
                              (body
                               (list "root /srv/www/html/gnucode.me/site/craggy-hurd/rendered/;")))
                             ;; (nginx-location-configuration
                             ;;  (uri "/agenda/")
                             ;;  (body
                             ;;   (list
                             ;;    (string-append "root " srv-root-dir "gnucode.me/agenda/;\n")
                             ;;          ;(string-append "auth_basic \"Yearly Agenda\";\n")
                             ;;          ;(string-append "auth_basic_user_file " srv-root-dir "gnucode.me/agenda/htpasswd;")
                             ;;    )))
                             )))
                          (nginx-server-configuration
                           (server-name '("gnu-hurd.com"))
                           (listen default-listen)
                           (root "/srv/www/html/gnu-hurd.com/")
                           (ssl-certificate (string-append letsencrypt-dir "gnu-hurd.com/fullchain.pem"))
                           (ssl-certificate-key (string-append letsencrypt-dir "gnu-hurd.com/privkey.pem"))
                           (raw-content default-raw-content)
                           (locations
                            (list
                             letsencrypt-acme-challenge  ;; for certbot
                             )))
                          (nginx-server-configuration
                           (server-name '("propernaming.org"))
                           (listen default-listen)
                           (root "/srv/www/html/propernaming.org/site/")
                           (ssl-certificate (string-append letsencrypt-dir "propernaming.org/fullchain.pem"))
                           (ssl-certificate-key (string-append letsencrypt-dir "propernaming.org/privkey.pem"))
                           (raw-content default-raw-content)
                           (locations
                            (list
                             letsencrypt-acme-challenge ;; for certbot
                             )))
                          )))))

            (service openssh-service-type
                     (openssh-configuration
                      (openssh openssh-sans-x)
                      (password-authentication? #f)
                      (port-number 22)
                      (authorized-keys
                       `(
                         ("joshua" ,(plain-file "id_rsa.pub" %joshua-ssh-key))
                         ("root" ,(plain-file "id_rsa.pub" %joshua-ssh-key))
                         ))))

            ;; I've created the prosody admin user, and I imported the cert...
            ;; but pidgin tells me that I the XMPP server at gnucode.me does not support encryption.
            (service prosody-service-type
                     (prosody-configuration
                      ;;(certificates "/etc/")
                      (admins '("jbranso@gnucode.me"))
                      (virtualhosts
                       (list
                        (virtualhost-configuration
                         (domain "gnucode.me"))))))

            ;; I can test send an email from my ssh machine via:
            ;; cat test-email.txt  | msmtp -- jbranso@dismail.de
            ;; (service opensmtpd-service-type
            ;;          (opensmtpd-configuration
            ;;           (config-file %smtpd.conf)))

            ;; TODO my nftables for a server ARE NOT working.
            ;; (service nftables-service-type
            ;;          (nftables-configuration
            ;;           (ruleset
            ;;            (plain-file "nftables.conf" %gnucode-nftables-ruleset))))

            (service opensmtpd-service-type
                     (let ([action-receive
                            (opensmtpd-local-delivery
                             (name "receive")
                             (method (opensmtpd-lmtp
                                      (destination "/var/run/dovecot/lmtp"))))
                            ;; (opensmtpd-local-delivery
                            ;;  (name "receive")
                            ;;  (method (opensmtpd-maildir
                            ;;           (pathname "/home/%{rcpt.user}/Maildir")
                            ;;           (junk #t)))
                            ;;  (virtual (opensmtpd-table
                            ;;            (name "vusers")
                            ;;            (data '(("joshua@gnucode.me"  . "joshua")
                            ;;                    )))))
                            ]
                           [pki-gnucode (opensmtpd-pki
                                         (domain "smtp.gnucode.me")
                                         (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                                         (key "/etc/letsencrypt/live/gnucode.me/privkey.pem"))]
                           [filter-dkimsign (opensmtpd-filter
                                             (name "dkimsign")
                                             (exec #t)
                                             (proc (list (file-append opensmtpd-filter-dkimsign "/libexec/opensmtpd/filter-dkimsign")
                                                         " -d gnucode.me -s 2023-02-28 -c relaxed/relaxed -k "
                                                         "/etc/opensmtpd/dkimsign/02-28-2023-rsa1024-gnucode.me-private.key "
                                                         "user nobody group nogroup")))]
                           ;; [table-creds (opensmtpd-table
                           ;;               (name "creds")
                           ;;               (data
                           ;;                (list
                           ;;                 (cons "joshua"
                           ;;                       "$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86."))))]
                           )
                       (opensmtpd-configuration
                        (interfaces
                         (list
                          ;; this forum help suggests that I listen on 0.0.0.0 and NOT eth0
                          ;; https://serverfault.com/questions/726795/opensmtpd-wont-work-at-reboot
                          ;; this listens for email from the outside world
                          (opensmtpd-interface  ; accept email from gmail and other domains
                           (interface "0.0.0.0")
                           (port 25)
                           (secure-connection "tls")
                           (pki pki-gnucode))
                          (opensmtpd-interface  ;; let joshua@gnucode.me send emails
                           (interface "0.0.0.0")
                           (port 465)
                           (secure-connection "smtps")
                           (pki pki-gnucode)
                           (auth #t)
                           (filters (list filter-dkimsign)))
                          (opensmtpd-interface ;; let joshua@gnucode.me send emails
                           (interface "0.0.0.0")
                           (port 587)
                           (secure-connection "tls-require")
                           (pki pki-gnucode)
                           (auth #t)
                           (filters (list filter-dkimsign)))))
                        (matches (list
                                  (opensmtpd-match
                                   (action (opensmtpd-relay
                                            (name "relay")))
                                   (options
                                    (list
                                     (opensmtpd-option
                                      (option "for any"))
                                     (opensmtpd-option
                                      (option "from any"))
                                     (opensmtpd-option
                                      (option "auth")))))
                                  (opensmtpd-match
                                   (action action-receive)
                                   (options
                                    (list
                                     (opensmtpd-option
                                      (option "from any"))
                                     (opensmtpd-option
                                      (option "for domain")
                                      (data (opensmtpd-table
                                             (name "vdoms")
                                             (data (list "gnucode.me"
                                                         "gnu-hurd.com"))))))))
                                  (opensmtpd-match
                                   (action action-receive)
                                   (options
                                    (list
                                     (opensmtpd-option
                                      (option "for local"))))))))))

            (service unattended-upgrade-service-type)

            %my-base-services)))

;; (list (machine
;;        (operating-system %system)
;;        (environment managed-host-environment-type)
;;        (configuration (machine-ssh-configuration
;;                        (host-name "45.56.66.20")
;;                        (system "x86_64-linux")
;;                        (user "joshua")
;;                        (identity "~/.ssh/id_rsa")
;;                        (host-key "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJgL0hBTWmCVGGvNJYa+YS+fEXs89v0GbdkQ+M+LdZlf root@(none)")
;;                        (port 22)))))
